#ifndef YHAIDA_WEBRELAY_H
#define YHAIDA_WEBRELAY_H
#include "tunnel.h"
#include "../../server/thread/ThreadLocalSingleton.h"
#include "../http/HttpContext.h"
#include "../http/HttpRequest.h"
#include "../http/HttpResponse.h"
#include "../http/HttpServer.h"
#include "../fastcgi/fastcgi.h"
#include <malloc.h>
#include <stdio.h>
#include <sys/resource.h>
#include <unistd.h>
#include <utility>
#include <unordered_set>
#include <boost/any.hpp>
#include <boost/circular_buffer.hpp>
#include <queue>

namespace yhaida
{
    using std::string;

    class WebRelay : Utils::nocapyable
    {
    public:
        WebRelay(EventLoop *loop,
                 const InetAddress &listenAddr,
                 const std::map<std::string, InetAddress> &backends,
                 int idleSeconds,
                 int numberTunnel);
        ~WebRelay()
        {
        }
        void setThreadNum(int numThreads)
        {
            _server.setThreadNum(numThreads);
        }

        void start()
        {
            _server.start();
        }

    private:
        void initPerThread(EventLoop *ioLoop);

        void onConnection(const TcpConnectionPtr &conn);

        void onMessage(const TcpConnectionPtr &conn,
                       Buffer *buffer,
                       Timestamp);

        void fastcgiBegin(Buffer* message);
        void fastcgiParams(Buffer* message,const std::string&);
        void fastcgiStdin(Buffer* message);
        void fastcgiRequest(const TcpConnectionPtr&conn,const std::string&);

        void onRequest(const TcpConnectionPtr &conn, const HttpRequest &req,HttpResponse *resp);

        void onTime();

        void dumpConnectionBuckets();

    private:
        typedef std::weak_ptr<yhaida::TcpConnection> WeakTcpConnectionPtr;

        struct Node
        {
            explicit Node(const WeakTcpConnectionPtr &weakConn)
                : _weakConn(weakConn)
            {
            }
            ~Node()
            {
                yhaida::TcpConnectionPtr conn = _weakConn.lock();
                if (conn)
                {
                    conn->shutdown();
                }
            }
            WeakTcpConnectionPtr _weakConn;
        };
        struct Type
        {
            std::unordered_set<std::string> _type;
            Type(){};
            void add(std::string type)
            {
                _type.insert(std::move(type));
            }
            std::unordered_set<std::string>& getType()
            {
                return _type;
            }
        };

        typedef std::shared_ptr<Node> NodePtr;
        typedef std::weak_ptr<Node> WeakNodePtr;
        typedef std::unordered_set<NodePtr> Bucket;
        typedef boost::circular_buffer<Bucket> WeakConnectionList;

    private:
        typedef ThreadLocalSingleton<std::map<std::string, TunnelPtr>> _t_backends;
        
        typedef ThreadLocalSingleton<std::map <std::string,std::queue<TunnelPtr> > > _t_FreeConnLists;
        typedef ThreadLocalSingleton<std::map <std::string,std::queue<TunnelPtr> > > _t_KeepAliveConnLists;//维持长连接
        typedef ThreadLocalSingleton<WeakConnectionList> _t_WeakConnectionList;

        TcpServer _server;
        std::map<std::string, InetAddress> _redirections;
        int _idleSeconds;
        int _numberTunnel;
    };
}
#endif